package com.azlogica.control;

import java.util.ArrayList;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;

import com.azlogica.entity.Frame;
import com.azlogica.gpslocation.PopUpActivity;

public class GpsService extends Service implements LocationListener,
		SensorEventListener {

	private SensorManager senSensorManager;
	private Sensor senAccelerometer;
	private boolean transmit = false;
	private ManageFrame mf;
	private String provider;
	Location location;
	int messType;
	private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
	private static final long MIN_TIME_BW_UPDATES = 3600000;
	protected LocationManager locationManager;

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		/*Sent unsent frames from localdatabase*/
		sentFrames();
		
		/*Receive the type of message from other activities or the AlarmBroadcast */
		Bundle extras = intent.getExtras();
		if (extras != null) {
			messType = extras.getInt("MESSTYPE");
		}
		
		/*Initialization of the Sensor (Accelerometer) and its listener*/
		senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		senAccelerometer = senSensorManager
				.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		senSensorManager.registerListener(this, senAccelerometer,
				SensorManager.SENSOR_DELAY_NORMAL);

		/*Initialization of the ManageFrame it communicates with the dao interface to save all
		 * the frame in the local database*/
		this.mf = new ManageFrame(this);
		
		/*Initialization of GPS location provider. The app asks if the user wants to turn on the
		 * gps if it's turned off*/
		this.locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			Intent intentPop = new Intent(this, PopUpActivity.class);
			intentPop.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(intentPop);
		}
		
		/*Get the best provider GPS or Wi-FI to get the locations*/
		Criteria criteria = new Criteria();
		this.provider = locationManager.getBestProvider(criteria, false);
		this.locationManager.requestLocationUpdates(provider,
				MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
		
		/*Checks if it is the first transmition*/
		if (locationManager != null) {
			location = locationManager.getLastKnownLocation(provider);
		}

		if (location != null) {
			getLocation();
		}

		return super.onStartCommand(intent, flags, startId);
	}

	public void createFrameOnDatabase(Frame f) {
		/*Create the frame on the database*/
		 mf.createFrame(f.getHeader(), f.getReport(), f.getSack(),
		 f.getMessType(), f.getImei(), f.getStatus(), f.getNumber(),
		 f.getAccuracy(), f.getSpeed(), f.getAzimuth(), f.getAltitude(),
		 f.getLongitude(), f.getLatitude(), f.getGpsUTC(), f.getMcc(),
		 f.getMnc(), f.getLac(), f.getCllId(), f.getBattery(),
		 f.getSendTime());
	}

	public void sendData(byte[] frame, int id) {
		//AZLogica Server2
		//Connection con = new Connection("190.146.239.42", 11000, frame);
		//Localhost
		Connection con = new Connection(this,"10.0.2.2", 11000, frame, id);
		con.execute();
	}

	public void getLocation() {
		/*Get the location if the transmit boolean (If the user is walking) is true and
		 * if the message type is different to 0.
		 */
		if (messType != 0 && transmit) {
			Frame f = new Frame(location, this, messType);
			byte[] frame = mf.buildFrame(f);
			createFrameOnDatabase(f);
			sendData(frame,f.getId());
		}
	}
	
	public void sentFrames(){
		ArrayList<Frame> unsentFrames = new ArrayList<Frame>();
		for(Frame f:unsentFrames){
			byte[] frame = mf.buildFrame(f);
			createFrameOnDatabase(f);
			sendData(frame,f.getId());
		}
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		/*Checks if the accelerometer receive any kind of movement. Change the transmit boolean state.*/
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			float kFilteringFactor = 0.6f;
			float[] accelerometer_values = event.values.clone();
			float[] gravity = { 0.0f, 0.0f, 0.0f };
			float[] linear_acceleration = { 0.0f, 0.0f, 0.0f };
			gravity[0] = (accelerometer_values[0] * kFilteringFactor)
					+ (gravity[0] * (1.0f - kFilteringFactor));
			gravity[1] = (accelerometer_values[1] * kFilteringFactor)
					+ (gravity[1] * (1.0f - kFilteringFactor));
			gravity[2] = (accelerometer_values[2] * kFilteringFactor)
					+ (gravity[2] * (1.0f - kFilteringFactor));

			linear_acceleration[0] = (accelerometer_values[0] - gravity[0]);
			linear_acceleration[1] = (accelerometer_values[1] - gravity[1]);
			linear_acceleration[2] = (accelerometer_values[2] - gravity[2]);

			float magnitude = 0.0f;
			magnitude = (float) Math.sqrt(linear_acceleration[0]
					* linear_acceleration[0] + linear_acceleration[1]
					* linear_acceleration[1] + linear_acceleration[2]
					* linear_acceleration[2]);
			magnitude = Math.abs(magnitude);
			if (magnitude > 3) {
				transmit = true;
			} else {
				transmit = false;
			}

		}
	}

	@Override
	public void onLocationChanged(Location location) {
		/*Calls getLocation() method if the distance moved was higher than x meters*/		
		Location lastLocation = locationManager.getLastKnownLocation(provider);
		float distanceMoved = lastLocation.distanceTo(location);
		if (distanceMoved>100){
			messType=1;
			getLocation();
		}
		messType=0;
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onProviderDisabled(String provider) {
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
	}
}
